﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace Silvermoon.Controls
{
    /// <summary>
    /// Panel that flips between nodes but only shows only node, even when paned.
    /// </summary>
    public class FlipPanel : NavigationBase
    {
        private INavigationNode previousNode;
        private INavigationNode nextNode;

        public override void SelectNode(INavigationNode node, bool animated)
        {
            if (!animated || node == this.selectedNode) base.SelectNode(node, false);
            else
            {
                INavigationNode next = this.selectedNode;
                INavigationNode prev = this.selectedNode;
                while (!SelectedNodeFoundOrEmpty(next, prev, node))
                {
                    if (next != null) next = next.Next;
                    if (prev != null) prev = prev.Previous;
                }
                if (next == node)
                {
                    previousNode = selectedNode;
                    NavigateTo(node, +1f);
                }
                else if (prev == node)
                {
                    nextNode = selectedNode;
                    NavigateTo(node, -1f);
                }
            }
        }

        protected override void OnLayout()
        {
            if (CheckFlag(InvalidationFlag.Size | InvalidationFlag.Layout))
            {
                LayoutContent();
            }
            base.OnLayout();
        }

        private void LayoutContent()
        {
            VisibleControls.Clear();
            LayoutNode(SelectedNode, 0f);
            if (previousNode != null && offset > 0f) LayoutNode(previousNode, -1f);
            else if (nextNode != null && offset < 0f) LayoutNode(nextNode, 1f);
            containerGenerator.ReleaseUnusedContainers();
        }

        private void LayoutNode(INavigationNode node, float delta)
        {
            if (node != null)
            {
                Control control = containerGenerator.GetContainerFromData(node);
                if (control != null)
                {
                    VisibleControls.Add(control);
                    InitializeControl(control);
                    Rectangle bounds = control.Margin.LayoutChild(this.ClientBounds);
                    bounds.X += (int)((delta + Offset) * Width);
                    control.Bounds = bounds;
                }
            }
        }

        private bool SelectedNodeFoundOrEmpty(INavigationNode next, INavigationNode prev, INavigationNode node)
        {
            if (next == node || prev == node) return true;
            return (next == null && prev == null);
        }

        public override void NavigateToNext()
        {
            previousNode = selectedNode;
            base.NavigateToNext();
        }

        protected override void PanInternal(PanEventArgs e)
        {
            base.PanInternal(e);
            if (offset > 0) previousNode = selectedNode != null ? selectedNode.Previous : null;
            else if (offset < 0) nextNode = selectedNode != null ? selectedNode.Next : null;
        }

        public override void NavigateToPrevious()
        {
            nextNode = selectedNode;
            base.NavigateToPrevious();
        }

        protected override void OnOffsetChanged()
        {
            base.OnOffsetChanged();
            if (offset == 0f)
            {
                previousNode = null;
                nextNode = null;
            }
            Invalidate(InvalidationFlag.Layout);
        }

        protected override void OnSelectedNodeChanged(INavigationNode oldValue)
        {
            this.previousNode = this.nextNode = oldValue;
            Invalidate(InvalidationFlag.Layout);
            base.OnSelectedNodeChanged(oldValue);

        }

        protected override void OnSyncControl(object sender, SyncEventArgs e)
        {
            if (e.Reason == SynEventReason.Pan)
            {
                float offset = e.Offset;
                previousNode = selectedNode.Previous;
                nextNode = selectedNode.Next;
            }
            base.OnSyncControl(sender, e);
        }

        protected override void SyncNavigateTo(INavigationNode node, float offset)
        {
            if (offset > 0f) offset = this.offset + 1f; else offset = this.offset - 1f;
            base.SyncNavigateTo(node, offset);
        }
    }
}
